﻿using System;
using System.Collections.Generic;
using JetBrains.Application;
using JetBrains.DataFlow;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Caches;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Files;
using JetBrains.ReSharper.Psi.Tree;
using System.Linq;
using JetBrains.Util;
using SPCAFContrib.ReSharper.Common.Attributes;

namespace SPCAFContrib.ReSharper.Common.Psi.CSharpCache
{
    [PsiComponent]
    [Applicability(
       IDEProjectType.SP2010FarmSolution |
       IDEProjectType.SP2013FarmSolution)]
    public class WcfInterfaceCache : SPPsiCacheBase<SPWcfInterface>
    {
        #region Properties
        protected override string CacheDirectoryName
        {
            get { return "WcfInterfaces"; }
        }

        public override IEqualityComparer<SPWcfInterface> ItemsEqualityComparer
        {
            get { return new WcfInterfaceCacheEqualityComparer(); }
        }

        public static WcfInterfaceCache GetInstance(ISolution solution)
        {
            return solution.GetComponent<WcfInterfaceCache>();
        } 
        #endregion

        #region Ctor
        public WcfInterfaceCache(IShellLocks locks, ISolution solution, ChangeManager changeManager,
            Lifetime lifetime, IPsiConfiguration psiConfiguration, LanguageManager languageManager,
            IPersistentIndexManager persistentIndexManager)
            : base(locks, solution, changeManager, lifetime, psiConfiguration, languageManager, persistentIndexManager)
        {
        }
        #endregion

        #region Methods

        #region Overrided methods
        protected override IList<SPWcfInterface> BuildData(IPsiSourceFile sourceFile)
        {
            JetHashSet<SPWcfInterface> jetHashSet = null;
            IFile file = sourceFile.GetDominantPsiFile<CSharpLanguage>();

            if (file != null)
            {
                ICSharpFile xmlFile = file as ICSharpFile;

                xmlFile.NamespaceDeclarationsEnumerable.ForEach(__ => __.TypeDeclarationsEnumerable.Where(
                    _ => _ is IInterfaceDeclaration && CheckInterfaceAttributes(_)).ForEach(_ =>
                    {
                        if (jetHashSet == null)
                            jetHashSet = new JetHashSet<SPWcfInterface>(ItemsEqualityComparer);

                        jetHashSet.Add(new SPWcfInterface()
                        {
                            Title = _.CLRName,
                            Offset = _.GetTreeStartOffset(),
                            SourceFileFullPath = sourceFile.GetLocation().Directory.FullPath,
                            SourceFileName =  sourceFile.Name
                        });
                    }));
            }

            if (jetHashSet == null)
                return null;
            else
                return jetHashSet.ToArray();
        }
        
        protected override bool ShouldBeProcessed(IPsiSourceFile sourceFile)
        {
            bool result = false;

            IFile file = sourceFile.GetDominantPsiFile<CSharpLanguage>();
            if (file != null)
            {
                if (file is ICSharpFile)
                {
                    ICSharpFile xmlFile = file as ICSharpFile;
                    
                    result =
                        xmlFile.NamespaceDeclarationsEnumerable.Any(__ => __.TypeDeclarations.Any(
                            _ => _ is IInterfaceDeclaration && CheckInterfaceAttributes(_)));
                }
            }

            return result;
        }

        #endregion

        #region Implementation details

        private bool CheckInterfaceAttributes(ICSharpTypeDeclaration cSharpTypeDeclaration)
        {
            return cSharpTypeDeclaration.AttributesEnumerable.Any(_ => _.Name.ShortName == "ServiceContract");
        }

        #endregion

        #endregion
    }

    [Serializable()]
    public class SPWcfInterface : SPPsiCacheItem
    {
        public string Title { get; set; }
    }

    public class WcfInterfaceCacheEqualityComparer : IEqualityComparer<SPWcfInterface>
    {
        public bool Equals(SPWcfInterface x, SPWcfInterface y)
        {
            return x.Offset.Equals(y.Offset) &&
                   String.Equals(x.Title.Trim(), y.Title.Trim(), StringComparison.OrdinalIgnoreCase);
        }

        public int GetHashCode(SPWcfInterface obj)
        {
            return (obj.Title.Trim()).GetHashCode() ^ obj.Offset.GetHashCode();
        }
    }
}
